package logic

import (
	"context"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v9"
	"github.com/olivere/elastic/v7"
	goredislib "github.com/redis/go-redis/v9"
	"goods_srv/global"
	"goods_srv/goods_proto"
	"goods_srv/initialize"
	"goods_srv/model"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"
	"time"
)

type Server struct {
	goods_proto.UnimplementedGoodsServer
}

func (s *Server) GoodsListByHot(ctx context.Context, in *goods_proto.GoodsListByHotRequest) (*goods_proto.GoodsListByHotResponse, error) {
	var goods []model.Goods
	tx := global.DB.Preload("Category").Preload("Comment").Order("is_hot desc").Find(&goods)
	if tx.Error != nil {
		return nil, status.Errorf(codes.Internal, "查询失败")
	}
	var goodsList []*goods_proto.GoodsInfo
	for _, v := range goods {
		goodsList = append(goodsList, &goods_proto.GoodsInfo{
			Id:         int64(v.ID),
			Name:       v.Name,
			CategoryId: int64(v.CategoryId),
			Logo:       v.Logo,
			Price:      float32(v.Price),
			Image:      v.Image,
			CommentId:  int64(v.CommentId),
			Stock:      int64(v.Stock),
			IsHot:      int64(v.IsHot),
		})
	}
	return &goods_proto.GoodsListByHotResponse{GoodsInfo: goodsList}, nil
}

// es列表
func (s *Server) GoodsList(ctx context.Context, in *goods_proto.GoodsListRequest) (*goods_proto.GoodsListResponse, error) {
	termQuery := elastic.NewTermQuery("goods", in.Keywords)
	num, list := initialize.GetGoods(termQuery)
	var goodsList []*goods_proto.GoodsInfo
	for _, v := range list {
		goodsList = append(goodsList, &goods_proto.GoodsInfo{
			Id:         int64(v.ID),
			Name:       v.Name,
			CategoryId: int64(v.CategoryId),
			Logo:       v.Logo,
			Price:      float32(v.Price),
			Image:      v.Image,
			CommentId:  int64(v.CommentId),
			Stock:      int64(v.Stock),
			IsHot:      int64(v.IsHot),
		})
	}
	return &goods_proto.GoodsListResponse{GoodsInfo: goodsList, Total: num}, nil
}

func (s *Server) GoodsDetail(ctx context.Context, in *goods_proto.GoodsDetailRequest) (*goods_proto.GoodsInfo, error) {
	var comment model.Comment
	global.DB.Where(&model.Comment{GoodsId: int(in.Id)}).First(&comment)
	var goods model.Goods
	global.DB.Preload("Comment").Where(&model.Goods{Model: gorm.Model{ID: uint(in.Id)}}).First(&goods)
	return &goods_proto.GoodsInfo{
		Id:         int64(goods.ID),
		Name:       goods.Name,
		CategoryId: int64(goods.CategoryId),
		Logo:       goods.Logo,
		Price:      float32(goods.Price),
		Image:      goods.Image,
		CommentId:  int64(goods.CommentId),
		Comment:    comment.Comments,
		Stock:      int64(goods.Stock),
		IsHot:      int64(goods.IsHot),
	}, nil
}

func (s *Server) CreateComment(ctx context.Context, in *goods_proto.CreateCommentRequest) (*goods_proto.Empty, error) {
	client := goredislib.NewClient(&goredislib.Options{
		Addr: "127.0.0.1:6379",
	})
	pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...)
	rs := redsync.New(pool)
	mutexName := "goods-mutex"
	mutex := rs.NewMutex(mutexName, redsync.WithExpiry(10*time.Second), redsync.WithTries(5))

	if err := mutex.LockContext(ctx); err != nil {
		return nil, status.Errorf(codes.Internal, "获取redis锁失败")
	}
	tx := global.DB.Begin()
	var goods model.Goods
	result := tx.Where(&model.Goods{Model: gorm.Model{ID: uint(in.GoodsId)}}).First(&goods)
	if result.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Errorf(codes.Internal, "商品不存在")
	}
	comment := model.Comment{
		GoodsId:  int(in.GoodsId),
		Comments: in.Comments,
	}
	save := tx.Save(&comment)
	if save.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Errorf(codes.Internal, "添加评论失败")
	}
	tx.Commit()
	if ok, err := mutex.UnlockContext(ctx); !ok || err != nil {
		return nil, status.Errorf(codes.Internal, "释放redis锁失败")
	}
	return &goods_proto.Empty{}, nil
}

func (s *Server) AddShopping(ctx context.Context, in *goods_proto.AddShoppingRequest) (*goods_proto.Empty, error) {
	client := goredislib.NewClient(&goredislib.Options{
		Addr: "127.0.0.1:6379",
	})
	pool := goredis.NewPool(client) // or, pool := redigo.NewPool(...)
	rs := redsync.New(pool)
	mutexName := "shopping-mutex"
	mutex := rs.NewMutex(mutexName, redsync.WithExpiry(10*time.Second), redsync.WithTries(5))

	if err := mutex.LockContext(ctx); err != nil {
		return nil, status.Errorf(codes.Internal, "获取redis锁失败")
	}
	tx := global.DB.Begin()
	var goods model.Goods
	result := tx.Where(&model.Goods{Model: gorm.Model{ID: uint(in.GoodsId)}}).First(&goods)
	if result.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Errorf(codes.Internal, "商品不存在")
	}
	shopping := model.Shopping{
		GoodsId: int(in.GoodsId),
		Num:     int(in.Num),
	}
	save := tx.Save(&shopping)
	if save.RowsAffected == 0 {
		tx.Rollback()
		return nil, status.Errorf(codes.Internal, "添加评论失败")
	}
	tx.Commit()
	if ok, err := mutex.UnlockContext(ctx); !ok || err != nil {
		return nil, status.Errorf(codes.Internal, "释放redis锁失败")
	}
	return &goods_proto.Empty{}, nil
}
